package elev.sim;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * TODO OPIS KLASY
 *
 * @author Marcin Samułek
 */
public class Kontroler {

    private int id;
    private ArrayList<Winda> windy = new ArrayList<>();
    private ArrayList<Pietro> wszystkiePietra = new ArrayList<>();
    private List<Pietro> wszystkieZgloszenia = new ArrayList<>();

    /**
     * Tworzy piętra.
     */
    Kontroler() {
        this.id = 0;
        for (int i = 0; i <= 7; i++) {
            this.wszystkiePietra.add(new Pietro(i));
        }
    }

    /**
     *
     * @param iloscWind
     * @param pojemnosc
     */
    public void uruchomWindy(int iloscWind, int pojemnosc) {
        if (this.windy.isEmpty()) {
            boolean tryb;
            int numerWindy = 0;
            while (iloscWind > 0) {
                tryb = (iloscWind % 2 == 0) ? true : false;
                this.windy.add(new Winda(tryb, pojemnosc));
                iloscWind--;
                this.windy.get(numerWindy).setNumerWindy(numerWindy);
                if (tryb) {
                    this.windy.get(numerWindy).setPietro(7);
                }
                numerWindy++;
            }
            //nie dziala wyłaczenie wind
            if (iloscWind > 0) {
                windy.get(0).czyUruchomiona = Statystyki.isCzyUruchomionaWinda1();
            }
            if (iloscWind > 1) {
                windy.get(1).czyUruchomiona = Statystyki.isCzyUruchomionaWinda2();
            }
        }
    }

    private Pietro pobierzPietro(int nr) {
        return this.wszystkiePietra.get(nr);
    }

    /**
     * dodaje wezwanie windy
     *
     * @param numerPietra od ktorego zaczyna
     * @param pk pietro koncowe
     */
    public void dodajWezwanie(int numerPietra, int pk) {
        this.wszystkiePietra.get(numerPietra).dodajPasazera(this.id, numerPietra, pk);
        if ((pk - numerPietra) > 0) {
            if (!this.wszystkiePietra.get(numerPietra).getGora()) {
                this.wszystkiePietra.get(numerPietra).setGora();
                this.wszystkieZgloszenia.add(this.pobierzPietro(numerPietra));
            }
        } else {
            if (!this.wszystkiePietra.get(numerPietra).getDol()) {
                this.wszystkiePietra.get(numerPietra).setDol();
                this.wszystkieZgloszenia.add(this.pobierzPietro(numerPietra));
            }
        }
        this.id++;
    }

    /**
     * Rozdziela aktualne wezwania windom.
     */
    public void rozdzielWezwania() {
        for (int i = 0; i < this.windy.size(); i++) {
            this.rozdzielWezwania(i);
        }
    }

    public boolean rozdzielWezwania(int nr) {
        boolean tr = this.windy.get(nr).getTryb();
        int x = 0;
        while (this.wszystkieZgloszenia.size() > x) {
            if (tr == true && this.wszystkieZgloszenia.get(x).getGora()) {
                windy.get(nr).dodajWezwanie(this.wszystkieZgloszenia.get(x).getPietro());
                this.wszystkieZgloszenia.remove(x);
                return true;
            } else if (tr == false && this.wszystkieZgloszenia.get(x).getDol()) {
                windy.get(nr).dodajWezwanie(this.wszystkieZgloszenia.get(x).getPietro());
                this.wszystkieZgloszenia.remove(x);
                return true;
            } else {
                x++;
            }
        }
        this.windy.get(nr).switchTryb();
        return false;
    }

    public boolean rozdzielWezwaniaMax(int nr) {
        boolean tr = this.windy.get(nr).getTryb();
        int x = 0;
        int max = 0;
        int n = 0;
        while (this.wszystkieZgloszenia.size() > x) {
            if (tr == true && this.wszystkieZgloszenia.get(x).getGora()) {
                if (max < this.wszystkieZgloszenia.get(x).getOczekujacy()) {
                    max = this.wszystkieZgloszenia.get(x).getOczekujacy();
                    n = x;
                }
                x++;
            } else if (tr == false && this.wszystkieZgloszenia.get(x).getDol()) {
                if (max < this.wszystkieZgloszenia.get(x).getOczekujacy()) {
                    max = this.wszystkieZgloszenia.get(x).getOczekujacy();
                    n = x;
                }
                x++;
            } else {
                x++;
            }
        }
        if (n != 0) {
            windy.get(nr).dodajWezwanie(this.wszystkieZgloszenia.get(n).getPietro());
            this.wszystkieZgloszenia.remove(n);
            return true;
        }
        this.windy.get(nr).switchTryb();
        return false;
    }

    /**
     * symulacja ruchu w jednej jednostce czasowej - jedna zmiana pietra windy.
     * algorytm priorytetowy bez dobierania
     */
    public void krok() {
        for (int w = 0; w < this.windy.size(); w++) {
            int np = this.windy.get(w).getPietro();
            Pietro p = this.wszystkiePietra.get(np);
            if (this.windy.get(w).getCel() == -1) {
                boolean rest;
                rest = this.windy.get(w).obsluzZdarzenie(p);
                this.windy.get(w).ustawWinde();
                if (rest == false) {
                    this.wszystkieZgloszenia.add(this.pobierzPietro(np));
                }

                if (this.windy.get(w).getCel() == -1) {
                    this.rozdzielWezwania(w);
                    this.windy.get(w).ustawWinde();
                }
            } else {
                this.windy.get(w).jedz();
            }
        }
        for (int nw = 0; nw < this.windy.size(); nw++) {
            if (windy.get(nw).getCel() != -1) {
                Statystyki.dodajCzasPrzebiegu(nw);
                System.out.println("winda " + windy.get(nw).getNumerWindy() + " czas " + Statystyki.getCzasPrzebiegu(nw));
            }
        }
    }

    /*
     * algorytm priorytetowy z dobieraniem
     */
    public void krok1() {
        for (int w = 0; w < this.windy.size(); w++) {
            int np = this.windy.get(w).getPietro();
            Pietro p = this.wszystkiePietra.get(np);
            if (this.windy.get(w).getCel() == -1) {
                boolean rest;
                rest = this.windy.get(w).obsluzZdarzenie(p);
                this.windy.get(w).ustawWinde();
                if (rest == false) {
                    this.wszystkieZgloszenia.add(this.pobierzPietro(np));
                }

                if (this.windy.get(w).getCel() == -1) {
                    this.rozdzielWezwania(w);
                    this.windy.get(w).ustawWinde();
                }
            } else {
                if (this.checkPersons(np, this.windy.get(w).getTryb())) {
                    boolean rest;
                    rest = this.windy.get(w).obsluzZdarzenie(p);
                    if (rest == false) {
                        this.wszystkieZgloszenia.add(this.pobierzPietro(np));
                    }
                } else {
                    this.windy.get(w).jedz();
                }
            }
        }
        for (int nw = 0; nw < this.windy.size(); nw++) {
            if (windy.get(nw).getCel() != -1) {
                Statystyki.dodajCzasPrzebiegu(nw);
                System.out.println("winda " + windy.get(nw).getNumerWindy() + " czas " + Statystyki.getCzasPrzebiegu(nw));
            }
        }
    }

    /*
     * algorytm priorytetowy, więcej wezwań ma pierwszeństwo
     */
    public void krok2() {
        for (int w = 0; w < this.windy.size(); w++) {
            int np = this.windy.get(w).getPietro();
            Pietro p = this.wszystkiePietra.get(np);
            if (this.windy.get(w).getCel() == -1) {
                boolean rest;
                rest = this.windy.get(w).obsluzZdarzenie(p);
                this.windy.get(w).ustawWinde();
                if (rest == false) {
                    this.wszystkieZgloszenia.add(this.pobierzPietro(np));
                }

                if (this.windy.get(w).getCel() == -1) {
                    this.rozdzielWezwaniaMax(w);
                    this.windy.get(w).ustawWinde();
                }
            } else {
                this.windy.get(w).jedz();
            }
        }
        for (int nw = 0; nw < this.windy.size(); nw++) {
            if (windy.get(nw).getCel() != -1) {
                Statystyki.dodajCzasPrzebiegu(nw);
                System.out.println("winda " + windy.get(nw).getNumerWindy() + " czas " + Statystyki.getCzasPrzebiegu(nw));
            }
        }
    }

    public boolean checkPersons(int nr, boolean tryb) {
        Pietro p;
        System.out.println(this.wszystkieZgloszenia.size());
        for (int i = 0; i < this.wszystkieZgloszenia.size(); i++) {
            p = this.wszystkieZgloszenia.get(i);
            System.out.println("Winda ejst na: " + nr + " zgloszenie na pietrze: " + p.getPietro());
            if (p.getPietro() == nr) {
                if (p.getGora() == tryb || p.getDol() == !tryb) {
                    System.out.println("Usuwam");
                    this.wszystkieZgloszenia.remove(i);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *
     * @param winda
     * @return
     */
    public int getPietro(int winda) {
        return this.windy.get(winda).getPietro();
    }

    /*
     * @param winda @return
     */
    /**
     *
     * @param winda
     * @return
     */
    public int getOsoby(int winda) {
        return this.windy.get(winda).ilePas();
    }

    public int getPrzewiezioneOsoby(int pietro) {
        return wszystkiePietra.get(pietro).getPrzywezieni();
    }

    /**
     * Zwraca detaliczny widok osob na jednym pietrze
     *
     * @param numer numer pietra
     * @return
     */
    public HashMap<Integer, Integer> getOsobyCount(int numer) {
        HashMap<Integer, Integer> pasazerowie = new HashMap<>();
        for (int p = 0; p < this.wszystkiePietra.get(numer).getOczekujacy(); p++) {
            pasazerowie.put(numer, this.wszystkiePietra.get(numer).getOczekujacyArray(p).getPietroDocelowe());
        }
        return pasazerowie;
    }

    /*
     * zwraca rozkłąd pasażerów na piętrach
     */
    public HashMap<Integer, String> getOsobyAll() {
        HashMap<Integer, String> pasazerowie = new HashMap<>();
        for (int p = 0; p < this.wszystkiePietra.size(); p++) {
            pasazerowie.put(
                    this.wszystkiePietra.get(p).getPietro(),
                    this.wszystkiePietra.get(p).getDestinations());
        }
        return pasazerowie;
    }

    /**
     * Zwraca całkowita ilosc osob na jednym pietrze
     *
     * @param nr numer pietra
     * @return
     */
    public int getOsobyTotalCount(int nr) {
        return this.wszystkiePietra.get(nr).getOczekujacy();
    }

    public boolean czyWszystkieRozwiezione() {
        int iloscPieter = 8;
        int iloscWind = 2;
        boolean czyCzekaja = false;
        boolean czyJada = false;
        //sprawdzenie czy na pietrach nikt juz nie czeka
        for (int i = 0; i < iloscPieter; i++) {
            if (getOsobyTotalCount(i) > 0) {
                czyCzekaja = true;
                break;
            }
        }
        //sprawdzeni czy winda kogos nie rozwozi
        for (Winda w : windy) {
            if (w.ilePas() > 0) {
                czyJada = true;
                break;
            }
        }
        if (!czyJada && !czyCzekaja) {
            return true;
        }
        return false;
    }

    public void resetujWindy() {
        this.windy.clear();
        this.wszystkiePietra.clear();
        this.wszystkieZgloszenia.clear();
        this.id = 0;
        for (int i = 0; i <= 7; i++) {
            this.wszystkiePietra.add(new Pietro(i));
        }
    }
}
